/*******************************************************************************/
/*                                                                             */
/*  Copyright (c) 2009: Peter Schregle,                                        */
/*  All rights reserved.                                                       */
/*                                                                             */
/*  This file is part of the Property Library.                                 */
/*                                                                             */
/*  Redistribution of the Property Library and use in source and binary forms, */
/*  with or without modification, are permitted provided that the following    */
/*  conditions are met:                                                        */
/*  1. Redistributions of source code must retain the above copyright notice,  */
/*     this list of conditions and the following disclaimer.                   */
/*  2. Redistributions in binary form must reproduce the above copyright       */
/*     notice, this list of conditions and the following disclaimer in the     */
/*     documentation and/or other materials provided with the distribution.    */
/*  3. Neither the name of Peter Schregle nor the names of other contributors  */
/*     may be used to endorse or promote products derived from this software   */
/*     without specific prior written permission.                              */
/*                                                                             */
/*  THIS SOFTWARE IS PROVIDED BY PETER SCHREGLE AND CONTRIBUTORS 'AS IS' AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE      */
/*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE */
/*  ARE DISCLAIMED. IN NO EVENT SHALL PETER SCHREGLE OR CONTRIBUTORS BE LIABLE */
/*  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
/*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS    */
/*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      */
/*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,        */
/*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN   */
/*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE            */
/*  POSSIBILITY OF SUCH DAMAGE.                                                */
/*                                                                             */
/*******************************************************************************/


#ifndef __property_rome_h__
#define __property_rome_h__

#include <boost/operators.hpp>
#include <boost/function.hpp>

namespace pl {

/******************************************************************************/
/*                                                                            */
/* property_rome                                                              */
/*                                                                            */
/******************************************************************************/

template <
	/// The type of the property.
	typename T,
	/// The type of the parent.
	typename P>
/// A read-only property, backed by an external read method and firing read
/// events.
//!
//! Aside from initialization, you cannot write new values to this property.
class property_rome
	: boost::unit_steppable<pl::property_rome<T, P>
	>
{
	/// The parent of the property.
	P * parent_;

	/// The type of the getter function.
	typedef boost::function<T & ()> getter_type;

	/// The getter function.
	//!
	//! The getter function must be implemented on the parent object. It needs 
	//! to be passed when this property is constructed.
	getter_type getter_;


	/// No copy construction.
	property_rome(pl::property_rome<T, P> const&);

	/// No copy assignment.
	pl::property_rome<T, P> & operator =(pl::property_rome<T, P> const&);

	/// The internal get function.
	//!
	//! The get function ensures that the events are properly raised.
	T & get()
	{
		T & value = getter_();
		if (on_get) 
			on_get(parent_, value);
		return value;
	}

	/// The internal get function.
	//!
	//! The get function ensures that the events are properly raised.
	T const& get() const
	{
		T const& value = getter_();
		if (on_get) 
			on_get(parent_, value);
		return value;
	}

public:

	/// The value type of the property.
	typedef T value_type;

	/// The parent type of the property.
	typedef P parent_type;

	/// Type of the on_get event.
	//!
	//! The on_get event is fired whenever the value of the property is read.
	//! When the read is carried out the on_get function is called with the
	//! signature void on_get_event(P const* parent, T const& value).
	//!
	//! If you handle the event, you are passed a const pointer to the parent of
	//! the property, as well as a const reference to the property value.
	typedef boost::function<void (P const*, T const&)> on_get_type;

	/// The on_get event.
	//!
	//! If you assign a matching function to this event, the function will be
	//! called whenever the event is fired.
	//!
	//! The on_get event is fired whenever the value of the property is read.
	//! When the read is carried out the on_get function is called with the
	//! signature void on_get_event(P const* parent, T const& value).
	//!
	//! If you handle the event, you are passed a const pointer to the parent of
	//! the property, as well as a const reference to the property value.
	static on_get_type on_get;

public:

	/// Default construction of the property.
	property_rome(
		/// The getter function of the parent object.
		getter_type getter)
		: parent_(0)
		, getter_(getter)
	{ }

	/// Access the property value.
	//!
	//! \return The property value.
	operator T & ()
	{
		return get();
	}
};

template<typename T, typename P> 
typename pl::property_rome<T,P>::on_get_type pl::property_rome<T,P>::on_get;


} // namespace pl


#endif // __property_rome_h__
